#include <iostream>
#include <string.h>
#ifndef _WIN32
#include <signal.h>
#endif // !_WIN32

#include "event.h"

// SIGING 信号处理函数
// fd: 文件描述符； what: 事件类型； arg: 传递的参数
static void sig_int(evutil_socket_t fd, short what, void *arg) {
    std::cout << "ctrl + c" << std::endl;
}

// SIGTERM(kill) 信号处理函数
// fd: 文件描述符； what: 事件类型； arg: 传递的参数
static void sig_term(evutil_socket_t fd, short what, void *arg) {
    std::cout << "kill" << std::endl;

    // 如果处于非待决，再次添加到libevent中，否则信号只会被响应一次
    event *ev = (event*)arg;
    if (!evsignal_pending(ev, NULL)) {
        event_del(ev);
        event_add(ev, NULL);
    }
}

int main(int argc, char* argv[])
{
#ifdef _WIN32
    // 初始化socket库
    WSADATA wsa;
    WSAStartup(MAKEWORD(2, 2), &wsa);
#else
    // 忽略管道信号，因为发送数据给已关闭的socket会生成SIGPIPE信号，导致进程退出
    if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
        return -1;
#endif

    std::cout << "libevent signal test" << std::endl;

    // 创建libevent上下文
    event_base *base = event_base_new();
    if (!base) {
        std::cout << "event_base_new failed" << std::endl;
        return -1;
    }
    std::cout << "event_base_new success" << std::endl;

    // 添加 ctrl + c 信号事件，处于no pending状态
    // evsignal_new隐藏的状态 EV_SIGNAL|EV_PERSIST
    event *ev_sigint = evsignal_new(base, SIGINT, sig_int, base);
    if (!ev_sigint) {
        std::cerr << "SIGINT evsignal_new failed" << std::endl;
        return -1;
    }

    // 添加事件到pending
    if (event_add(ev_sigint, 0) != 0) {
        std::cerr << "SIGINT event_add failed" << std::endl;
        return -1;
    }

    // 添加kill信号，非持久，只进入一次
    event *ev_sigterm = event_new(base, SIGTERM, EV_SIGNAL, sig_term, event_self_cbarg());
    if (!ev_sigterm) {
        std::cerr << "SIGTERM event_new failed" << std::endl;
        return -1;
    }

    // 添加事件到pending
    if (event_add(ev_sigterm, 0) != 0) {
        std::cerr << "SIGTERM event_add failed" << std::endl;
        return -1;
    }

    // 进入事件主循环
    event_base_dispatch(base);

    // 释放资源
    event_free(ev_sigint);
    event_base_free(base);

    return 0;
}
